{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"UTF-8\""
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### pry-docの読み込み\n",
    "require \"/root/jupyter/vendor/bundle/ruby/2.3.0/gems/pry-doc-0.10.0/lib/pry-doc\"\n",
    "#require \"/Users/ftakao2007/jupyter/vendor/bundle/ruby/2.3.0/gems/pry-doc-0.10.0/lib/pry-doc\"\n",
    "### エンコーディングをUTF-8に設定\n",
    "Encoding.default_external = \"UTF-8\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 概要\n",
    "\n",
    "* Railsでのrspecの使い方について"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# インストール\n",
    "\n",
    "* Gemfile\n",
    "\n",
    "```\n",
    "================================================\n",
    "group :development, :test do\n",
    "  # Call 'byebug' anywhere in the code to stop execution and get a debugger console\n",
    "  gem 'byebug', platform: :mri\n",
    "  gem 'rspec-rails'      # 追加\n",
    "  gem 'capybara'         # 追加 (findやcheckメソッドが使えるようになる)\n",
    "end\n",
    "================================================\n",
    "```\n",
    "\n",
    "インストール手順\n",
    "\n",
    "```\n",
    "### インストールと初期ファイル作成\n",
    "$ bundle install --path vendor/bundle\n",
    "$ bundle exec rails generate rspec:install\n",
    "================================================\n",
    "      create  .rspec\n",
    "      create  spec\n",
    "      create  spec/spec_helper.rb\n",
    "      create  spec/rails_helper.rb\n",
    "================================================\n",
    "\n",
    "### rails_helper.rb にCapybaraの設定を追記\n",
    "$ vi spec/rails_helper.rb\n",
    "================================================\n",
    "require 'rspec/rails'\n",
    "require 'capybara/rails'   # 追加\n",
    "require 'capybara/rspec'   # 追加\n",
    "...\n",
    "RSpec.configure do |config|\n",
    "  config.include Capybara::DSL     # 追加\n",
    "================================================\n",
    "\n",
    "### モデルやコントローラを作成したときに自動でRspecファイルも作成されるようにする\n",
    "### config.generatorsのところを追加\n",
    "$ vi config/application.rb\n",
    "================================================\n",
    "...\n",
    "module Blog\n",
    "  class Application < Rails::Application\n",
    "    # Settings in config/environments/* take precedence over those specified here.\n",
    "    # Application configuration should go into files in config/initializers\n",
    "    # -- all .rb files in that directory are automatically loaded.\n",
    "    config.generators do |g|\n",
    "      g.test_framework = \"rspec\"\n",
    "      #g.controller_specs = false     # controllerのRspecファイルを作成しない場合はコメントアウトを外す\n",
    "      #g.helper_specs = false     # helperのRspecファイルを作成しない場合はコメントアウトを外す\n",
    "      #g.view_specs = false     # viewのRspecファイルを作成しない場合はコメントアウトを外す\n",
    "    end\n",
    "  end\n",
    "end\n",
    "================================================\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "# frozen_string_literal: true\n",
      "source \"https://rubygems.org\"\n",
      "\n",
      "# gem \"rails\"\n",
      "\n",
      "gem 'ruby-ldap', '~> 0.9.11'\n",
      "gem 'rspec'\n",
      "\n",
      "Don't run Bundler as root. Bundler can ask for sudo if it is needed, and\n",
      "installing your bundle as root will break this application for all non-root\n",
      "users on this machine.\n",
      "Using diff-lcs 1.3\n",
      "Using rspec-support 3.6.0\n",
      "Using ruby-ldap 0.9.19\n",
      "Using bundler 1.14.6\n",
      "Using rspec-core 3.6.0\n",
      "Using rspec-expectations 3.6.0\n",
      "Using rspec-mocks 3.6.0\n",
      "Using rspec 3.6.0\n",
      "Bundle complete! 2 Gemfile dependencies, 8 gems now installed.\n",
      "Bundled gems are installed into /root/git_jupyter_notebook/Ruby/vendor/bundle.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "### Gemfileの確認\n",
    "File.open(\"Gemfile\") do |file|\n",
    "  puts file.read\n",
    "end\n",
    "\n",
    "### Jupyter上からインストールする場合はFullPATHで指定\n",
    "puts `bundle install --gemfile /root/git_jupyter_notebook/Ruby/Gemfile --path /root/git_jupyter_notebook/Ruby/vendor/bundle`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# テスト対象のファイル\n",
    "\n",
    "* model\n",
    "    * app/models/webmail/mail.rb\n",
    "\n",
    "```\n",
    "================================================\n",
    "class Webmail::Mail\n",
    "...\n",
    "  def score\n",
    "    0\n",
    "  end\n",
    "...\n",
    "================================================\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# テスト実行"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "ename": "Errno::ENOENT",
     "evalue": "No such file or directory @ rb_sysopen - spec/models/webmail/mail_spec.rb",
     "output_type": "error",
     "traceback": [
      "\u001b[31mErrno::ENOENT\u001b[0m: No such file or directory @ rb_sysopen - spec/models/webmail/mail_spec.rb",
      "\u001b[37m(pry):5:in `initialize'\u001b[0m",
      "\u001b[37m(pry):5:in `open'\u001b[0m",
      "\u001b[37m(pry):5:in `<main>'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/gems/pry-0.10.4/lib/pry/pry_instance.rb:355:in `eval'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/gems/pry-0.10.4/lib/pry/pry_instance.rb:355:in `evaluate_ruby'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/gems/pry-0.10.4/lib/pry/pry_instance.rb:323:in `handle_line'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/gems/pry-0.10.4/lib/pry/pry_instance.rb:243:in `block (2 levels) in eval'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/gems/pry-0.10.4/lib/pry/pry_instance.rb:242:in `catch'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/gems/pry-0.10.4/lib/pry/pry_instance.rb:242:in `block in eval'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/gems/pry-0.10.4/lib/pry/pry_instance.rb:241:in `catch'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/gems/pry-0.10.4/lib/pry/pry_instance.rb:241:in `eval'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/gems/iruby-0.3/lib/iruby/backend.rb:66:in `eval'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/gems/iruby-0.3/lib/iruby/backend.rb:12:in `eval'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/gems/iruby-0.3/lib/iruby/kernel.rb:87:in `execute_request'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/gems/iruby-0.3/lib/iruby/kernel.rb:47:in `dispatch'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/gems/iruby-0.3/lib/iruby/kernel.rb:37:in `run'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/gems/iruby-0.3/lib/iruby/command.rb:70:in `run_kernel'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/gems/iruby-0.3/lib/iruby/command.rb:34:in `run'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/gems/iruby-0.3/bin/iruby:5:in `<top (required)>'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/bin/iruby:22:in `load'\u001b[0m",
      "\u001b[37m/root/jupyter/vendor/bundle/ruby/2.3.0/bin/iruby:22:in `<main>'\u001b[0m"
     ]
    }
   ],
   "source": [
    "### specディレクトリの作成\n",
    "Dir.mkdir('spec') unless Dir.exist?('spec')\n",
    "\n",
    "### spec/models/webmail/mail_spec.rbファイルの作成\n",
    "File.open(\"spec/models/webmail/mail_spec.rb\", \"w\") do |file|\n",
    "file.write <<-EOS\n",
    "require 'rails_helper'\n",
    "\n",
    "RSpec.describe Webmail::Mail, type: :model do\n",
    "  describe \"#score\" do\n",
    "    it \"returns 0 for an all gutter mail\" do\n",
    "      mail = Webmail::Mail.new\n",
    "      expect(mail.score).to eq(0)\n",
    "    end\n",
    "  end\n",
    "end\n",
    "EOS\n",
    "end\n",
    "\n",
    "\n",
    "### テスト実行\n",
    "puts `RAILS_ENV=development bundle exec rspec -fd spec/models/webmail/mail_spec.rb`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "実行ログ例\n",
    "\n",
    "```\n",
    "Webmail::Mail\n",
    "  #score\n",
    "    returns 0 for an all gutter mail\n",
    "\n",
    "Finished in 0.01226 seconds (files took 1.92 seconds to load)\n",
    "1 example, 0 failures\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# FactoryGirl\n",
    "\n",
    "* 概要\n",
    "    * テストデータを自動で作って投入してくれる"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## インストール\n",
    "\n",
    "```\n",
    "### Gemfileの修正\n",
    "$ vi Gemfile\n",
    "================================================\n",
    "   gem 'rspec-rails'\n",
    "   gem 'factory_girl_rails'   ### このへんに追加\n",
    "   gem 'capybara', '~> 2.13'\n",
    "================================================\n",
    "$ bundle install --path vendor/bundle\n",
    "\n",
    "### テスト用DB設定 (developやproductionと同じにしてるとデータが壊される可能性があるので)\n",
    "$ vi config/database.yml\n",
    "================================================\n",
    "test:\n",
    "...\n",
    "  database: test_blog\n",
    "...\n",
    "================================================\n",
    "\n",
    "### テストDBに値が保存されるように設定を修正(trueだと保存されない)\n",
    "### http://qiita.com/a_ishidaaa/items/b17ca8fa1a50ed5c3802\n",
    "$ vi spec/rails_helper.rb\n",
    "================================================\n",
    "  config.use_transactional_fixtures = false\n",
    "================================================\n",
    "\n",
    "### DB作成\n",
    "$ RAILS_ENV=test bundle exec rake db:create\n",
    "$ RAILS_ENV=test bundle exec rake db:migrate\n",
    "\n",
    "### FactoryGirl用ディレクトリとファイルの追加\n",
    "$ mkdir spec/factories\n",
    "$ vi spec/factories/articles.rb\n",
    "================================================\n",
    "FactoryGirl.define do\n",
    "  factory :article do\n",
    "    title \"MyString\"  ### この辺がテストデータ\n",
    "    text \"MyText\"\n",
    "  end\n",
    "end\n",
    "================================================\n",
    "\n",
    "### テストの追加\n",
    "$ vi spec/models/article_spec.rb\n",
    "================================================\n",
    "require 'rails_helper'\n",
    "\n",
    "RSpec.describe Article, type: :model do\n",
    "  #pending \"add some examples to (or delete) #{__FILE__}\"\n",
    "  describe \"#テスト実行\" do\n",
    "    context \"ArticleのFactoryを作成した場合\" do\n",
    "      it \"テストデータが作成される\" do \n",
    "        ### factories/articles.rbの値が入る\n",
    "        article_model = FactoryGirl.create(:article)\n",
    "        ### 以下にするとtextフィールドの値がhogehogeに上書きされる\n",
    "        #article_model = FactoryGirl.create(:article, text: \"hogehoge\")\n",
    "\n",
    "        ### 実行画面にテストデータを表示する\n",
    "        p article_model\n",
    "      end\n",
    "    end\n",
    "  end\n",
    "end\n",
    "================================================\n",
    "\n",
    "### テストの実行\n",
    "$ bundle exec rspec -fd\n",
    "================================================\n",
    "...\n",
    "Article\n",
    "  #テスト実行\n",
    "    ArticleのFactoryを作成した場合\n",
    "#<Article id: 13, title: \"MyString\", text: \"MyText\", created_at: \"2017-08-15 05:51:58\", updated_at: \"2017-08-15 05:51:58\">\n",
    "      テストデータが作成される\n",
    "...\n",
    "================================================\n",
    "\n",
    "$ mysql -ujupyter -p -e 'select * from test_blog.articles'\n",
    "================================================\n",
    "+----+----------+----------+---------------------+---------------------+\n",
    "| id | title    | text     | created_at          | updated_at          |\n",
    "+----+----------+----------+---------------------+---------------------+\n",
    "| 12 | MyString | hogehoge | 2017-08-15 05:34:54 | 2017-08-15 05:34:54 |  ### 上書きする方で投入したテストデータ\n",
    "| 13 | MyString | MyText   | 2017-08-15 05:51:58 | 2017-08-15 05:51:58 |\n",
    "+----+----------+----------+---------------------+---------------------+\n",
    "================================================\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# エラー対応"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `NoMethodError: undefined method 'document' for nil:NilClass`\n",
    "\n",
    "### 原因\n",
    "\n",
    "The reason for this error is that RSpec doesn't render views for controller specs by default. \n",
    "\n",
    "### 対策\n",
    "\n",
    "You can enable view rendering for a particular group of specs like this:\n",
    "```\n",
    "================================================\n",
    "describe FooController, type: :controller do\n",
    "  render_views\n",
    "\n",
    "  # write your specs\n",
    "end\n",
    "================================================\n",
    "```\n",
    "\n",
    "or you can enable it globally by adding this somewhere in your RSpec config:\n",
    "\n",
    "```\n",
    "================================================\n",
    "RSpec.configure do |config|\n",
    "  config.render_views\n",
    "end\n",
    "================================================\n",
    "```\n",
    "\n",
    "### 参考\n",
    "\n",
    "[undefined method 'document' for nil:NilClass while running Rails-tutorial with rspec](https://stackoverflow.com/questions/36949205/undefined-method-document-for-nilnilclass-while-running-rails-tutorial-with-r)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Ruby 2.4.1",
   "language": "ruby",
   "name": "ruby"
  },
  "language_info": {
   "file_extension": ".rb",
   "mimetype": "application/x-ruby",
   "name": "ruby",
   "version": "2.4.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
